﻿using Kaskelot.SP.Core;
using Microsoft.SharePoint;
using Stockholm.SOA.Kaskelot.WCF.DataContracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Precio.SharePoint.Core.Extensions;
using Kaskelot.SP.Model.Contracts;

namespace Kaskelot.SP.Services
{
	public class DocumentService
	{
		private SPList EnsureLibrary(SPSite site, string title, string description)
		{
			SPWeb web = site.RootWeb;
			SPList docLib = null;

			try
			{
				docLib = web.Lists.TryGetList(title);

				if (docLib == null)
				{
					Guid listId = Guid.Empty;
					listId = web.Lists.Add(title, description, SPListTemplateType.DocumentLibrary);
					docLib = web.Lists[listId];
				}
			}
			catch (Exception ex)
			{
				Logger.LogError(this, LayerNames.Services, "EnsureLibrary", ex.Message, ex);
			}

			return docLib;
		}

		public SPList EnsureDocumentLibrary(SPSite site, Val val)
		{
			SPList docLib = EnsureLibrary(site, "Byggnadsdokument " + val.Namn + " " + val.Id.ToString(), "Dokument för byggnader");

			val.DocumentLibraryId = docLib.ID;
			using (ValService vSvc = new ValService())
			{
				vSvc.UpdateVal(val, true);
			}

			return docLib;
		}

		public SPList EnsureTemplateLibrary(SPSite site)
		{
			return EnsureLibrary(site, Constants.TemplateLibrary.TemplateLibraryName, Constants.TemplateLibrary.TemplateLibraryName);
		}

		public SPList EnsureTempLibrary(SPSite site)
		{
			return EnsureLibrary(site, Constants.TempLibrary.TempLibraryName, Constants.TempLibrary.TempLibraryName);
		}

		public IEnumerable<Document> GetDocumentsByByggnad(SPSite site, Byggnad byggnad)
		{
			List<Document> result = new List<Document>();

			Guid siteId = site.ID;
			SPSecurity.RunWithElevatedPrivileges(delegate() {
				using (SPSite elvSite = new SPSite(siteId))
				{
					SPFolder folder = GetByggnadFolder(elvSite, byggnad);
					if (folder != null)
					{
						SPList list = folder.ParentWeb.Lists[folder.ParentListId];
						SPQuery query = new SPQuery();
						query.Folder = folder;
						query.RowLimit = 1000;
						query.ViewFields = GetViewFields();
						query.Query = string.Format("<OrderBy><FieldRef Name='{0}' Ascending='{1}'/></OrderBy>", "FileLeafRef", true);

						Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "Before query start");
						SPListItemCollection items = list.GetItems(query);
						items.Cast<SPListItem>()
							.ToList()
							.ForEach((SPListItem item) =>
							{
								if (item.FileSystemObjectType == SPFileSystemObjectType.File)
								{
									result.Add(MapFile(item));
								}
							});

						Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "After query and mapping");
					}
				}
			});

			return result;
		}

		public IEnumerable<Document> GetTemplates(SPSite site)
		{
			List<Document> result = new List<Document>();
			SPFolder folder = GetTemplateFolder(site);
			if (folder != null)
			{
				SPList list = folder.ParentWeb.Lists[folder.ParentListId];
				SPQuery query = new SPQuery();
				query.Folder = folder;
				query.RowLimit = 1000;
				query.ViewFields = GetViewFields();
				query.Query = string.Format("<OrderBy><FieldRef Name='{0}' Ascending='{1}'/></OrderBy>", "FileLeafRef", true);

				Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "Before query start");
				SPListItemCollection items = list.GetItems(query);
				items.Cast<SPListItem>()
					.ToList()
					.ForEach((SPListItem item) =>
					{
						if (item.FileSystemObjectType == SPFileSystemObjectType.File)
						{
							result.Add(MapFile(item));
						}
					});
				Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "After query and mapping");
			}

			return result;
		}

		public IEnumerable<Document> GetTempDocs(SPSite site)
		{
			List<Document> result = new List<Document>();
			SPFolder folder = GetTempFolder(site);
			if (folder != null)
			{
				SPList list = folder.ParentWeb.Lists[folder.ParentListId];
				SPQuery query = new SPQuery();
				query.Folder = folder;
				query.RowLimit = 1000;
				query.ViewFields = GetViewFields();
				query.Query = string.Format("<OrderBy><FieldRef Name='{0}' Ascending='{1}'/></OrderBy>", "FileLeafRef", true);

				Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "Before query start");
				SPListItemCollection items = list.GetItems(query);
				items.Cast<SPListItem>()
					.ToList()
					.ForEach((SPListItem item) =>
					{
						if (item.FileSystemObjectType == SPFileSystemObjectType.File)
						{
							result.Add(MapFile(item));
						}
					});
				Logger.LogVerbose(this, LayerNames.Services, "GetFolderContents", "After query and mapping");
			}

			return result;
		}

		public void DeleteDocument(SPSite site, Byggnad byggnad, int dokumentId)
		{
			bool unsafeWebStatus = site.RootWeb.AllowUnsafeUpdates;
			try
			{
				site.RootWeb.AllowUnsafeUpdates = true;
				SPList list = EnsureDocumentLibrary(site, ApplicationContext.Current.Val);
				SPListItem item = list.GetItemById(dokumentId);
				item.Recycle();
			}
			catch (Exception ex)
			{
				Logger.LogError(this, LayerNames.Services, "DeleteDocument", ex.Message, ex);
				throw;
			}
			finally
			{
				site.RootWeb.AllowUnsafeUpdates = unsafeWebStatus;
			}
		}

		public void DeleteTemplate(SPSite site, int dokumentId)
		{
			bool unsafeWebStatus = site.RootWeb.AllowUnsafeUpdates;
			try
			{
				site.RootWeb.AllowUnsafeUpdates = true;
				SPList list = EnsureTemplateLibrary(site);
				SPListItem item = list.GetItemById(dokumentId);
				item.Recycle();
			}
			catch (Exception ex)
			{
				Logger.LogError(this, LayerNames.Services, "DeleteTemplate", ex.Message, ex);
				throw;
			}
			finally
			{
				site.RootWeb.AllowUnsafeUpdates = unsafeWebStatus;
			}
		}

		public void DeleteTempDoc(SPSite site, int dokumentId)
		{
			try
			{
				SPList list = EnsureTempLibrary(site);
				SPListItem item = list.GetItemById(dokumentId);
				item.Recycle();
			}
			catch (Exception ex)
			{
				Logger.LogError(this, LayerNames.Services, "DeleteTempDoc", ex.Message, ex);
				throw;
			}
		}

		public SPFolder GetByggnadFolder(SPSite site, Byggnad byggnad)
		{
			SPWeb web = site.RootWeb;
			if (byggnad.DocumentFolderId.HasValue)
			{
				return web.GetFolder(byggnad.DocumentFolderId.Value);
			}
			else
			{
				bool allowUnsafe = web.AllowUnsafeUpdates;

				try
				{
					SPList docLib = EnsureDocumentLibrary(site, ApplicationContext.Current.Val);

					web.AllowUnsafeUpdates = true;
					SPFolder folder = docLib.RootFolder.SubFolders.Add(UrlUtil.CleanFileName(byggnad.Namn));
					folder.Update();
					byggnad.DocumentFolderId = folder.UniqueId;

					using (ByggnadService bSvc = new ByggnadService())
					{
						bSvc.UpdateByggnad(byggnad, true);
					}

					return folder;
				}
				catch (Exception ex)
				{
					Logger.LogError(this, LayerNames.Services, "GetByggnadFolder", "Error creating folder for byggnad.", ex);
					return null;
				}
				finally
				{
					web.AllowUnsafeUpdates = allowUnsafe;
				}
			}
		}

		public SPFolder GetTemplateFolder(SPSite site)
		{
			SPList list = EnsureTemplateLibrary(site);
			return list.RootFolder;
		}

		public SPFolder GetTempFolder(SPSite site)
		{
			SPList list = EnsureTempLibrary(site);
			return list.RootFolder;
		}

		private bool FolderExists(SPFolder folder)
		{
			try
			{
				if (folder != null && folder.Exists)
					return true;
				else
					return false;
			}
			catch (ArgumentException)
			{
				return false;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public SPFolder GetEArkivFolder(SPSite site)
		{
			try
			{
				GetTempFolder(site).SubFolders["eArkiv"].Delete();
			}
			catch (Exception) { }

			return GetTempFolder(site).SubFolders.Add("eArkiv");
		}

		public SPFolder GetLISAFolder(SPSite site)
		{
			try
			{
				GetTempFolder(site).SubFolders["LISA"].Delete();
			}
			catch (Exception) { }

			return GetTempFolder(site).SubFolders.Add("LISA");
		}

		public SPFolder GetSkatteverketFolder(SPSite site)
		{
			try
			{
				GetTempFolder(site).SubFolders["Skatteverket"].Delete();
			}
			catch (Exception) { }

			return GetTempFolder(site).SubFolders.Add("Skatteverket");
		}

		private Document MapFile(SPListItem item)
		{
			Document result;
			result = new Document()
			{
				Id = item.ID,
				FileName = item[SPBuiltInFieldId.FileLeafRef] as string,
				Url = item[SPBuiltInFieldId.FileRef] as string,
				Skapad = (DateTime)item[SPBuiltInFieldId.Created],
				Andrad = (DateTime)item[SPBuiltInFieldId.Modified],
				Type = Model.Contracts.Document.DocumentType.Document
			};

			return result;
		}

		private string GetViewFields()
		{
			return @"<FieldRef Name='FileRef' />
					<FieldRef Name='FileLeafRef' />
					<FieldRef Name='Editor' />
					<FieldRef Name='Modified' />
					<FieldRef Name='Created' />
					<FieldRef Name='Author' />
					<FieldRef Name='ContentType' />
					<FieldRef Name='URL' />
					<FieldRef Name='ParentFolderId' />";
		}

		// Från StackOverflow - http://stackoverflow.com/questions/17812209/use-sharepoint-copy-web-service-to-copy-folder-and-contents
		public void CopyFolderContents(SPSite site, Val oldVal, Val newVal)
		{
			string destinationURL = "Byggnadsdokument " + newVal.Namn + " " + newVal.Id.ToString();
			SPList docLib = null;
			SPSecurity.RunWithElevatedPrivileges(delegate()
			{
				using (SPSite elvSite = new SPSite(site.ID))
				{
					bool unsafeWebStatus = elvSite.RootWeb.AllowUnsafeUpdates;
					//bool formDigestSettings = elvSite.WebApplication.FormDigestSettings.Enabled;

					SPWeb rootWeb = elvSite.RootWeb;
					try
					{
						//elvSite.WebApplication.FormDigestSettings.Enabled = false;
						rootWeb.AllowUnsafeUpdates = true;

						if (!newVal.DocumentLibraryId.HasValue)
						{
							Guid listId = rootWeb.Lists.Add(destinationURL, "Dokument för byggnader", SPListTemplateType.DocumentLibrary);
							rootWeb.Update();

							newVal.DocumentLibraryId = listId;
							using (ValService vSvc = new ValService())
							{
								vSvc.UpdateVal(newVal);
							}

							docLib = rootWeb.Lists[newVal.DocumentLibraryId.Value];
						}

						SPFolder oFolder = EnsureDocumentLibrary(elvSite, oldVal).RootFolder;

						SPFileCollection collFile = oFolder.Files;
						foreach (SPFile oFile in collFile)
						{
							oFile.CopyTo(destinationURL + "/" + oFile.Name, true);
						}

						SPFolderCollection collFolder = oFolder.SubFolders;

						string[] folderURLs = new String[collFolder.Count];
						int i = 0;
						foreach (SPFolder subFolder in collFolder)
						{
							folderURLs[i++] = subFolder.Url;
						}
						for (i = 0; i < folderURLs.Length; i++)
						{
							SPFolder folder = collFolder[folderURLs[i]];
							if (folder.Name == "Forms")
								continue;

							string s = docLib.RootFolder.Url + "/" + folder.Name;
							folder.CopyTo(s);
						}
					}
					catch (Exception ex)
					{
						Logger.LogError(this, LayerNames.Services, "CopyFolderContents", ex.Message, ex);
					}
					finally
					{
						rootWeb.AllowUnsafeUpdates = unsafeWebStatus;
						//elvSite.WebApplication.FormDigestSettings.Enabled = formDigestSettings;
					}
				}
			});
		}
	}
}
